﻿using SocketTool.Com.Args;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SocketTool.Com.UDP.Group
{
    public class UDPGroup : ISocket
    {
        private UdpClient mClient;
        private IPEndPoint mLocalEndPoint;
        private IPEndPoint mGroupEndPoint;
        private int mReceiveSize = 1024 * 1024;
        private Thread mRecvThread = null;
        private bool mRecving = true;
        public CustomerProtocol Protocols { get; private set; }

        public event EventHandler<ConnectionArgs> SocketConnectionChangedEvent;
        public event EventHandler<ReceiveMessageArgs> ReceiveMessageEvent;

        public UDPGroup(string ip, int port, string localip, int localport)
        {
            this.mGroupEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
            this.mLocalEndPoint = new IPEndPoint(IPAddress.Parse(localip), localport);

            this.mClient = new UdpClient(port);
            this.mClient.JoinMulticastGroup(IPAddress.Parse(ip));
            this.mClient.Client.ReceiveBufferSize = this.mReceiveSize;
            this.mRecvThread = new Thread(ReceiveMessage_All);
            this.mRecvThread.IsBackground = true;
            this.mRecvThread.Start();
        }

        public async void ReceiveMessage_All()
        {
            try
            {
                while (mRecving)
                {
                    if (this.mClient != null && this.mClient.Available > 0)
                    {
                        var result = await this.mClient.ReceiveAsync();

                        byte[] receiveBytes = result.Buffer;

                        if (receiveBytes.Length == 0)
                            continue;

                        var bt = this.Protocols.Parse(receiveBytes, out int readLength);
                        this.ReceiveMessageEvent?.Invoke(this, new Args.ReceiveMessageArgs(mLocalEndPoint, Encoding.UTF8.GetString(bt)));
                    }
                    Thread.Sleep(50);
                }
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex.Message);
                Console.ResetColor();
            }

        }

        public void Close()
        {
            this.mRecving = false;
            if (this.mRecvThread != null && this.mRecvThread.ThreadState != ThreadState.Stopped)
                this.mRecvThread = null;
            this.mClient.Close();
        }

        public bool Open()
        {
            return true;
        }

        public void Send(string msg, int count)
        {
            var msgBt = Encoding.UTF8.GetBytes(msg);
            var sendBt = this.Protocols.GetSendData(msgBt);
            for (int i = 0; i < count; i++)
            {
                this.mClient.Send(sendBt, sendBt.Length, this.mGroupEndPoint);
            }
        }

        public void SetCustomerProtocol(CustomerProtocol protocol)
        {
            this.Protocols = protocol;
        }
    }
}
